package engine

import (
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/sansaniot/ssiot-core/facade/env"
	js "github.com/dop251/goja"
	"ssdevice/internal/rule/model"
)

func Apply(data map[string]interface{}, sn string, msgType string) map[string]interface{} {
	//获取
	processors := getDevRule(sn)
	if len(processors) == 0 {
		return data
	}

	meta := map[string]interface{}{
		"devSn":   sn,
		"msgType": msgType,
	}

	var result map[string]interface{}
	var err error
	for _, p := range processors {
		//env.Log.Infof("sn %s, processor %s, run script %s\n", sn, p["processorId"], p["script"])
		result, err = RunScript(p["script"], data, meta)
		//env.Log.Infof("rule engine result is %v\n", result)

		data = result
		if err != nil {
			env.Log.Errorf("sn %s, processor %s, run script err %s", sn, p["processorId"], err)
			break
		}
	}

	env.Log.Infof("device %s rule engine result is %v\n", sn, result)
	return result
}

func getDevRule(sn string) []map[string]string {
	// 设备或产品是否存在规则
	cacheKey := fmt.Sprintf("%s:%s", model.RuleCacheKeyPrefix, sn)
	rule, err := env.Cache.HashGet(cacheKey, model.RuleChainKey)
	if err != nil || rule == "" {
		return nil
	}

	processors := make([]map[string]string, 0)
	err = json.Unmarshal([]byte(rule), &processors)
	if err != nil {
		return nil
	}

	// 执行规则
	//fmt.Printf("rule for sn %s is %v", sn, processors)
	return processors
}

// RunScript 应用规则
// data是数据，meta是元数据，包含sn, msgType等
func RunScript(script string, data map[string]interface{}, meta map[string]interface{}) (result map[string]interface{}, err error) {
	//脚本例子
	const SCRIPT = `
	function f(data, mata) {
        var result = {};
         result.b = data.a + 2;
         result.c = data.a + 3;
		return result;
	}
	`
	//初始化js引擎
	vm := js.New()
	//运行js,验证语法是否错误
	_, err = vm.RunString(script)
	if err != nil {
		return nil, err
	}

	fns, ok := js.AssertFunction(vm.Get("f"))
	if !ok || fns == nil {
		return nil, errors.New("illegal function")
	}

	//导出js函数
	var fn func(map[string]interface{}, map[string]interface{}) (map[string]interface{}, error)
	err = vm.ExportTo(vm.Get("f"), &fn)
	if err != nil {
		return nil, errors.New("export function fail")
	}

	//组装参数
	m := map[string]interface{}{}
	m["a"] = 1

	//执行函数获取返回值
	result, err = fn(data, meta)
	if err != nil {
		return nil, errors.New("execute function error")
	}

	return result, nil
}
